package com.example.pdfSplice.service;

import com.example.pdfSplice.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.util.Matrix;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * PDF处理服务
 */
@Service
@Slf4j
public class PdfService {
    
    // 存储上传的PDF文档，key为fileId
    private final Map<String, PDDocument> documentCache = new ConcurrentHashMap<>();
    
    // 毫米到点的转换比例 (1 inch = 72 points, 1 inch = 25.4 mm)
    private static final double MM_TO_POINTS = 72.0 / 25.4;
    
    // 点到毫米的转换比例
    private static final double POINTS_TO_MM = 25.4 / 72.0;
    
    /**
     * 上传PDF文件并解析页面信息
     */
    public List<PdfPageInfo> uploadPdf(MultipartFile file) throws IOException {
        String fileId = UUID.randomUUID().toString();
        String fileName = file.getOriginalFilename();
        
        // 加载PDF文档
        PDDocument document = Loader.loadPDF(file.getBytes());
        documentCache.put(fileId, document);
        
        List<PdfPageInfo> pageInfos = new ArrayList<>();
        PDFRenderer renderer = new PDFRenderer(document);
        
        // 解析每一页
        for (int i = 0; i < document.getNumberOfPages(); i++) {
            PDPage page = document.getPage(i);
            PdfPageInfo pageInfo = new PdfPageInfo();
            
            pageInfo.setFileName(fileName);
            pageInfo.setFileId(fileId);
            pageInfo.setPageIndex(i);
            pageInfo.setRotation(page.getRotation());
            
            // 获取页面尺寸并转换为毫米
            PDRectangle mediaBox = page.getMediaBox();
            pageInfo.setWidthMm(mediaBox.getWidth() * POINTS_TO_MM);
            pageInfo.setHeightMm(mediaBox.getHeight() * POINTS_TO_MM);
            
            // 生成缩略图
            try {
                BufferedImage image = renderer.renderImageWithDPI(i, 72, ImageType.RGB);
                // 根据页面实际尺寸计算缩略图尺寸，保持比例
                int thumbnailWidth = (int) (pageInfo.getWidthMm() * 2.5); // 使用与前端相同的缩放比例
                int thumbnailHeight = (int) (pageInfo.getHeightMm() * 2.5);
                BufferedImage thumbnail = createThumbnail(image, thumbnailWidth, thumbnailHeight);
                pageInfo.setThumbnailBase64(imageToBase64(thumbnail));
            } catch (IOException e) {
                log.error("生成缩略图失败: {}", e.getMessage());
            }
            
            pageInfos.add(pageInfo);
        }
        
        return pageInfos;
    }
    
    /**
     * 拼接PDF
     */
    public byte[] mergePdf(PdfMergeRequest request) throws IOException {
        PDDocument outputDocument = new PDDocument();
        
        try {
            // 处理每个目标页面
            for (TargetPageConfig targetPageConfig : request.getTargetPages()) {
                // 创建目标页面
                PDRectangle pageSize = new PDRectangle(
                    (float) (targetPageConfig.getWidthMm() * MM_TO_POINTS),
                    (float) (targetPageConfig.getHeightMm() * MM_TO_POINTS)
                );
                PDPage targetPage = new PDPage(pageSize);
                outputDocument.addPage(targetPage);
                
                // 在目标页面上绘制源页面
                try (PDPageContentStream contentStream = new PDPageContentStream(outputDocument, targetPage)) {
                    for (MergePageConfig mergeConfig : targetPageConfig.getSourcePages()) {
                        drawSourcePage(contentStream, mergeConfig, outputDocument, targetPage);
                    }
                }
            }
            
            // 将文档转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            outputDocument.save(outputStream);
            return outputStream.toByteArray();
            
        } finally {
            outputDocument.close();
        }
    }
    
    /**
     * 在目标页面上绘制源页面
     */
    private void drawSourcePage(PDPageContentStream contentStream, MergePageConfig mergeConfig, PDDocument outputDocument, PDPage targetPage) throws IOException {
        PDDocument sourceDocument = documentCache.get(mergeConfig.getSourceFileId());
        if (sourceDocument == null) {
            throw new IllegalArgumentException("找不到源PDF文档: " + mergeConfig.getSourceFileId());
        }
        
        PDPage sourcePage = sourceDocument.getPage(mergeConfig.getSourcePageIndex());
        PageTransform transform = mergeConfig.getTransform();
        
        try {
            // 使用LayerUtility来导入页面
            org.apache.pdfbox.multipdf.LayerUtility layerUtility = new org.apache.pdfbox.multipdf.LayerUtility(outputDocument);
            PDFormXObject form = layerUtility.importPageAsForm(sourceDocument, mergeConfig.getSourcePageIndex());
            
            // 保存图形状态
            contentStream.saveGraphicsState();
            
            // 裁切区域处理 - 支持两种方式
            // 只有当任意一个边距大于0时才进行四边距离裁切
            boolean hasMarginCrop = transform.getCropTop() > 0 || transform.getCropBottom() > 0 || 
                                  transform.getCropLeft() > 0 || transform.getCropRight() > 0;
            // 只有当宽度和高度都大于0时才进行矩形裁切
            boolean hasRectCrop = transform.getCropWidth() > 0 && transform.getCropHeight() > 0;
            
            if (hasMarginCrop) {
                // 新的四边距离裁切方式
                PDRectangle sourcePageSize = sourcePage.getMediaBox();
                float sourceWidthMm = (float) (sourcePageSize.getWidth() / MM_TO_POINTS);
                float sourceHeightMm = (float) (sourcePageSize.getHeight() / MM_TO_POINTS);
                
                // 计算裁切后的区域
                float cropX = (float) (transform.getCropLeft() * MM_TO_POINTS);
                float cropY = (float) (transform.getCropBottom() * MM_TO_POINTS);
                float cropWidth = (float) ((sourceWidthMm - transform.getCropLeft() - transform.getCropRight()) * MM_TO_POINTS);
                float cropHeight = (float) ((sourceHeightMm - transform.getCropBottom() - transform.getCropTop()) * MM_TO_POINTS);
                
                if (cropWidth > 0 && cropHeight > 0) {
                    contentStream.addRect(cropX, cropY, cropWidth, cropHeight);
                    contentStream.clip();
                }
            } else if (hasRectCrop) {
                // 旧的矩形裁切方式（兼容性）
                contentStream.addRect(
                    (float) (transform.getCropX() * MM_TO_POINTS),
                    (float) (transform.getCropY() * MM_TO_POINTS),
                    (float) (transform.getCropWidth() * MM_TO_POINTS),
                    (float) (transform.getCropHeight() * MM_TO_POINTS)
                );
                contentStream.clip();
            }
            
            // 正确的坐标系转换：前端坐标系 -> PDF坐标系
            // 前端：左上角(0,0)，Y轴向下
            // PDF：左下角(0,0)，Y轴向上
            
            // 获取目标页面高度（毫米）
            float targetPageHeightMm = (float) (targetPage.getMediaBox().getHeight() / MM_TO_POINTS);
            
            // 获取源页面尺寸（毫米）
            float sourcePageWidthMm = (float) (sourcePage.getMediaBox().getWidth() / MM_TO_POINTS);
            float sourcePageHeightMm = (float) (sourcePage.getMediaBox().getHeight() / MM_TO_POINTS);
            
            // X坐标直接使用（左对齐一致）
            float pdfX = (float) transform.getOffsetX();
            
            // Y坐标需要转换：PDF的Y = 目标页面高度 - 前端的Y - 源页面高度*缩放
            float pdfY = targetPageHeightMm - (float)transform.getOffsetY() - sourcePageHeightMm * (float)transform.getScaleY();
            
            // 调试日志
            System.out.println("目标页面高度: " + targetPageHeightMm + "mm");
            System.out.println("源页面高度: " + sourcePageHeightMm + "mm");
            System.out.println("前端坐标: (" + transform.getOffsetX() + "mm, " + transform.getOffsetY() + "mm)");
            System.out.println("PDF坐标: (" + pdfX + "mm, " + pdfY + "mm)");
            System.out.println("缩放: (" + transform.getScaleX() + ", " + transform.getScaleY() + ")");
            
            // 构建变换矩阵：先平移到最终位置
            Matrix matrix = Matrix.getTranslateInstance(
                (float) (pdfX * MM_TO_POINTS),
                (float) (pdfY * MM_TO_POINTS)
            );
            
            // 如果有旋转，需要以元素中心为旋转中心
            if (transform.getRotation() != 0) {
                // 计算元素在当前位置的中心点偏移（使用正确的宽度和高度）
                float centerOffsetX = (float) (sourcePageWidthMm * transform.getScaleX() * MM_TO_POINTS / 2);
                float centerOffsetY = (float) (sourcePageHeightMm * transform.getScaleY() * MM_TO_POINTS / 2);
                
                System.out.println("旋转角度: " + transform.getRotation() + "度");
                System.out.println("元素中心偏移: (" + (centerOffsetX/MM_TO_POINTS) + "mm, " + (centerOffsetY/MM_TO_POINTS) + "mm)");
                
                // 移动到中心点，旋转，再移回来
                matrix.concatenate(Matrix.getTranslateInstance(centerOffsetX, centerOffsetY));
                // 注意：前端CSS rotate是顺时针，PDF Matrix.getRotateInstance是逆时针，所以取负值
                matrix.concatenate(Matrix.getRotateInstance(Math.toRadians(-transform.getRotation()), 0, 0));
                matrix.concatenate(Matrix.getTranslateInstance(-centerOffsetX, -centerOffsetY));
            }
            
            // 应用缩放
            if (transform.getScaleX() != 1.0 || transform.getScaleY() != 1.0) {
                matrix.concatenate(Matrix.getScaleInstance(
                    (float) transform.getScaleX(), 
                    (float) transform.getScaleY()));
            }
            
            contentStream.transform(matrix);
            contentStream.drawForm(form);
            
        } finally {
            // 恢复图形状态
            contentStream.restoreGraphicsState();
        }
    }
    
    /**
     * 创建缩略图
     */
    private BufferedImage createThumbnail(BufferedImage original, int maxWidth, int maxHeight) {
        int originalWidth = original.getWidth();
        int originalHeight = original.getHeight();
        
        // 直接使用目标尺寸，不保持比例，让图片填满整个区域
        BufferedImage thumbnail = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = thumbnail.createGraphics();
        
        // 设置渲染质量
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        // 拉伸图片以填满整个区域
        g2d.drawImage(original, 0, 0, maxWidth, maxHeight, null);
        g2d.dispose();
        
        return thumbnail;
    }
    
    /**
     * 将图片转换为Base64编码
     */
    private String imageToBase64(BufferedImage image) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "PNG", outputStream);
        byte[] imageBytes = outputStream.toByteArray();
        return Base64.getEncoder().encodeToString(imageBytes);
    }
    
    /**
     * 清理缓存的文档
     */
    public void clearCache(String fileId) {
        PDDocument document = documentCache.remove(fileId);
        if (document != null) {
            try {
                document.close();
            } catch (IOException e) {
                log.error("关闭PDF文档失败: {}", e.getMessage());
            }
        }
    }
    
    /**
     * 清理所有缓存
     */
    public void clearAllCache() {
        documentCache.forEach((fileId, document) -> {
            try {
                document.close();
            } catch (IOException e) {
                log.error("关闭PDF文档失败: {}", e.getMessage());
            }
        });
        documentCache.clear();
    }
}
